#pragma once
// 用户管理模块，与数据库进行交互

#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <websocketpp/frame.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
typedef websocketpp::connection_hdl con_hdl;
typedef server::message_ptr msg_ptr;

#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <mutex>
#include <mysql/mysql.h>
#include <json/json.h>


#include "send_to_qml.hpp"
#include "FileManagement.hpp"


// 连接数据库的信息
const std::string host = "127.0.0.1";
const std::string user = "qbt";
const std::string password = "134256";
const std::string db = "WSChat";
const unsigned int port = 8099;


// 记录每一个在线的用户
class OnlineUser{
public:
    int user_id_;
    std::string nickname_;
    con_hdl hdl_;
    OnlineUser(int i, std::string n,con_hdl h): user_id_(i), nickname_(n), hdl_(h) { }
};

class UserMgt
{

public:
    UserMgt();
    ~UserMgt();
    static int create_user(std::string nickname, std::string password, con_hdl hdl, server* s,std::thread* thread_sever);
    static int user_login(std::string nickname, std::string password, con_hdl hdl);
    static int upload_user_avatar(int user_id, int image_size, con_hdl hdl);
    static int flush_user_info(int user_id, con_hdl hdl, server *s);
    static bool is_user_online(std::string nickname);
    static bool user_exists(std::string nickname);
    static con_hdl hdl_of_user(std::string nickname);
    static int id_of_nickname(std::string nickname);
    static std::string nickname_of_id(int user_id);
    static int user_logout(int user_id);
    static void mysql_my_init(MYSQL* &mysql);
    static void add_user_rela(std::string nickname_1,std::string nickname_2,std::string rela);
    static void flush_qml_friend_list(int id);
    static void send_friend_item_info_to_qml(int recv_id, int friend_id);
    static void set_user_info(int id, std::string* info);
    static std::string info_of_user(int id, std::string colum);
    static int id_of_hdl(con_hdl h);

    static void flush_user_info_with_name(std::string user_name,con_hdl hdl, server *s);
    

private:
    static FileMgt file_mgt_;
    static std::mutex cpp11_lock_;
    static std::vector<OnlineUser> online_users_; // 保存所有在线用户的昵称、id、链接句柄
};
std::mutex UserMgt::cpp11_lock_; // online_users_ 的锁
std::vector<OnlineUser> UserMgt::online_users_;
FileMgt UserMgt::file_mgt_;

// 用户登出
int UserMgt::user_logout(int user_id)
{
    // 把登出用户从“在线用户”vector中去掉
    std::vector<OnlineUser>::iterator it = online_users_.begin();
    cpp11_lock_.lock();
    for(;it != online_users_.end(); it++)
    {
        if(it->user_id_ == user_id)
        {
            online_users_.erase(it);
            break;
        }
    }
    cpp11_lock_.unlock();

    // 修改用户状态为离线
    MYSQL* mysql;
    mysql_my_init(mysql);
    std::string new_status = "offline";
    std::string query = "UPDATE user SET status = '" + new_status + 
    "' WHERE id = '" + std::to_string(user_id) + "'";
    mysql_query(mysql, query.c_str());
    std::cout << "用户登出 --- " << user_id << std::endl;
    mysql_close(mysql);
    return 1;
}

// 数据库连接，基本设置
void UserMgt::mysql_my_init(MYSQL* &mysql)
{
    mysql = mysql_init(nullptr); // mysql 可以被称为“句柄”
    if(mysql == nullptr)
        std::cerr << "mysql_init(nullptr) return null" << std::endl;
    if(mysql_real_connect(mysql,"127.0.0.1","qbt","134256","WSChat",
    8099,nullptr,0) == nullptr)
    {
        std::cerr << "数据库连接失败!!!" << std::endl;
        mysql_close(mysql);;
    }
    else
        mysql_set_character_set(mysql,"utf8");
}

// 用户是否存在
bool UserMgt::user_exists(std::string nickname)
{
    MYSQL* mysql;
    mysql_my_init(mysql);
    std::string query = "SELECT COUNT(*) FROM user WHERE nickname = '" + nickname + "'";
    mysql_query(mysql, query.c_str());
    MYSQL_RES* result = mysql_store_result(mysql);
    MYSQL_ROW row = mysql_fetch_row(result);
    int count = (row != nullptr) ? std::stoi(row[0]) : -1;
    if (count == 0)
    {
        mysql_free_result(result);
        mysql_close(mysql);
        return false;
    }
    else
    {
        mysql_free_result(result);
        mysql_close(mysql);
        return true;
    }
}


// 创建新用户
int UserMgt::create_user(std::string nickname, std::string password, con_hdl hdl, server* s,std::thread* thread_sever)
{
    std::cout << "UserMgt::create_user thread   " << std::this_thread::get_id() << std::endl;

    // 这个“静态成员方法”方的定义，写在类外，前面不能再加 static
    // 1.初始化
    MYSQL* mysql = mysql_init(nullptr); // mysql 可以被称为“句柄”
    if(mysql == nullptr)
        std::cerr << "mysql_init(nullptr) return null" << std::endl;

    // 2.连接
    if(mysql_real_connect(mysql,"127.0.0.1","qbt","134256","WSChat",
    8099,nullptr,0) == nullptr)
    {
        // std::cerr << "连接数据库失败！" << std::endl;
        mysql_close(mysql);
        return 0;
    }
    else
    {
        // std::cout << "连接数据库成功！" << std::endl;
        // 设置客户端的编码，默认使用 latin1，否则写入中文乱码
        mysql_set_character_set(mysql,"utf8"); 
    }
    
    // 3. 执行插入sql, 插入前判断用户昵称是否重复, 若重复则给 qml 客户端返回登陆失败
    // 构建插入语句，只插入昵称和密码
    std::string insert_query = 
    "INSERT INTO user (nickname, passwd) VALUES ('" + nickname + "', '" + password + "')";

    // 执行插入语句
    int ret = mysql_query(mysql, insert_query.c_str());

    if (ret != 0)
    {
        // 判断是否是唯一性约束冲突，即昵称重复
        // mysql 错误码 ER_DUP_ENTRY 1062
        if (mysql_errno(mysql) == 1062)
        {
            // std::cerr << "昵称重复，注册失败" << std::endl;
            // 返回给客户端注册失败的信息
            Json::Value root;
            root["op"] = "register_fail";
            root["reason"] = "昵称重复";
            std::string jsonString = root.toStyledString();
            send_to_qml::send_text(hdl, jsonString);
        }
        else
        {
            std::cerr << "插入数据失败: " << mysql_error(mysql) << std::endl;
        }
        mysql_close(mysql);
        return 0;
    }

    // std::cout << "user_mgt thread   " << std::this_thread::get_id() << std::endl;
    // std::cout << nickname << std::endl;
    // std::cout << password << std::endl;
    

    // 4.关闭连接
    mysql_close(mysql);


    // 5.插入成功，给客户端返回"注册成功"的信息    
    Json::Value root;
    root["op"] = "register_success";
    std::string jsonString = root.toStyledString(); // 转化为格式字符串，里面加了一些空格和换行符

    //std::cout << "用户管理模块: send_to_qml::send_text 前" << std::endl;
    send_to_qml::send_text(hdl,jsonString);
    //std::cout << "用户管理模块: send_to_qml::send_text 后" << std::endl;

    return 1;
}

// 用户表
// CREATE TABLE `user` (
//     `id` int(11) NOT NULL AUTO_INCREMENT,
//     `nickname` varchar(50) NOT NULL,
//     `passwd` varchar(70) NOT NULL,
//     `telnum` char(11),
//     `gender` enum('男', '女'),
//     `avatar` BLOB,
//     `status` varchar(32),
//     `connection_hdl` VARCHAR(255), -- 适当的长度
//     `m_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
//     PRIMARY KEY (`id`),
//     UNIQUE KEY `telnum` (`telnum`)
// ) ENGINE=InnoDB DEFAULT CHARSET=utf8;


// 用户登录
int UserMgt::user_login(std::string nickname, std::string password, con_hdl hdl)
{
    MYSQL* mysql;
    mysql_my_init(mysql);


    
    // 验证用户是否存在
    std::string query = "SELECT COUNT(*) FROM user WHERE nickname = '" + nickname + "'";
    mysql_query(mysql, query.c_str());
    MYSQL_RES* result = mysql_store_result(mysql);
    MYSQL_ROW row = mysql_fetch_row(result);
    int count = (row != nullptr) ? std::stoi(row[0]) : -1;
    if (count == 0)
    {
        mysql_free_result(result);
        mysql_close(mysql);
        Json::Value root;
        root["op"] = "login_fail";
        root["reason"] = "用户不存在!";
        std::string jsonString = root.toStyledString();
        send_to_qml::send_text(hdl, jsonString);
        return 0;
    }

    // 验证密码是否正确
    query = "SELECT passwd FROM user WHERE nickname = '" + nickname + "'";
    mysql_query(mysql, query.c_str());
    result = mysql_store_result(mysql);
    row = mysql_fetch_row(result);
    std::string passwd = (row != nullptr) ? row[0] : "";
    if(passwd != password)
    {
        mysql_free_result(result);
        mysql_close(mysql);
        Json::Value root;
        root["op"] = "login_fail";
        root["reason"] = "密码错误!";
        std::string jsonString = root.toStyledString();
        send_to_qml::send_text(hdl, jsonString);
        return 0;
    }
    else{
        // 登陆成功
        

        // 修改用户状态为在线
        std::string new_status = "online";
        query = "UPDATE user SET status = '" + new_status + 
        "' WHERE nickname = '" + nickname + "'";
        mysql_query(mysql, query.c_str());
        

        // 获取用户 id
        query = "SELECT id FROM user WHERE nickname = '" + nickname + "'";
        mysql_query(mysql, query.c_str());
        MYSQL_RES *result = mysql_store_result(mysql);
        MYSQL_ROW row = mysql_fetch_row(result);
        int user_id = std::stoi(row[0]);

        mysql_free_result(result);
        mysql_close(mysql);


        OnlineUser u(user_id, nickname, hdl);
        cpp11_lock_.lock();
        online_users_.push_back(u);
        cpp11_lock_.unlock();

        Json::Value root;
        root["op"] = "login_success";
        root["nickname"] = nickname;
        root["user_id"] = user_id;
        std::string jsonString = root.toStyledString();

        // std::cout << "准备send_to_qml::send_text" << std::endl;

        send_to_qml::send_text(hdl, jsonString);
        return 1;
    }

}

// 上传用户头像,这里是先收到客户端的上传请求，先给这个连接上来的 二进制数据 定个向
int UserMgt::upload_user_avatar(int user_id, int image_size, con_hdl hdl)
{
    hdlWithFileInfo hld_with_file;
    hld_with_file.hdl_ = hdl;
    hld_with_file.kind_ = "upload_user_avatar";
    hld_with_file.user_id_ = user_id;
    hld_with_file.file_size_ = image_size;
    file_mgt_.push_back(hld_with_file); // 信息放入，给接下来要到来的二进制数据定向

    // 告诉客户端,我定向好了,你可以开始发文件了
    Json::Value root;
    root["op"] = "ready";
    std::string jsonString = root.toStyledString();
    send_to_qml::send_text(hdl, jsonString);
    return 1;
}



// 刷新用户信息
int UserMgt::flush_user_info(int user_id, con_hdl hdl, server *s)
{
    
    // 查询用户昵称
    std::string nickname = info_of_user(user_id, "nickname");
    

    // 查询用户个性签名
    std::string signature = info_of_user(user_id, "signature");

    std::string gender = info_of_user(user_id, "gender");
    std::string tele = info_of_user(user_id, "telnum");
    

    // 告诉客户端,用户的昵称等
    Json::Value root;
    root["op"] = "info";
    root["nickname"] = nickname;
    root["signature"] = signature;
    root["gender"] = gender;
    root["tele"] = tele;
    std::string jsonString = root.toStyledString();
    send_to_qml::send_text(hdl, jsonString);
	
    
    // 调用文件传输模块的方法, 把此 id 用户的头像, 发送到连接 hdl 上
    file_mgt_.send_user_avatar(user_id, hdl, s);
}



// 判断用户是否在线
bool UserMgt::is_user_online(std::string nickname)
{
    if(nickname == "") return false;
    cpp11_lock_.lock();
    for(auto value : online_users_)
    {
        if(value.nickname_ == nickname)
        {
            std::cout << "UserMgt::is_user_online 用户 " << nickname << " 在线" << std::endl; 
            cpp11_lock_.unlock();
            return true;
        }
    }
    cpp11_lock_.unlock();
    return false;
}

con_hdl UserMgt::hdl_of_user(std::string nickname)
{
    std::cout << "con_hdl UserMgt::hdl_of_user" << nickname << std::endl;
    cpp11_lock_.lock();
    for(auto value : online_users_)
    {
        if(value.nickname_ == nickname)
        {
            cpp11_lock_.unlock();
            std::cout << "返回连接句柄nickname" << nickname << std::endl;
            return value.hdl_;
        }
    }
    cpp11_lock_.unlock();
}

int UserMgt::id_of_hdl(con_hdl h)
{
    cpp11_lock_.lock();
    for(auto value : online_users_)
    {
        if(value.hdl_.lock().get() == h.lock().get())
        {
            int id = value.user_id_;
            cpp11_lock_.unlock();
            return id;
        }
    }
    cpp11_lock_.unlock();
    return -1;
}

int UserMgt::id_of_nickname(std::string nickname)
{
    MYSQL* mysql;
    mysql_my_init(mysql);

    std::string query = "SELECT id FROM user WHERE nickname = '" + nickname + "'";
    mysql_query(mysql, query.c_str());
    MYSQL_RES* result = mysql_store_result(mysql);
    MYSQL_ROW row = mysql_fetch_row(result);
    int id = std::stoi(row[0]);
    mysql_free_result(result);
    mysql_close(mysql);
    return id;
}

std::string UserMgt::nickname_of_id(int user_id)
{
    if(user_id == -1) return "";

    MYSQL* mysql;
    mysql_my_init(mysql);

    std::string query = "SELECT nickname FROM user WHERE id = '" + std::to_string(user_id) + "'";
    mysql_query(mysql, query.c_str());
    MYSQL_RES* result = mysql_store_result(mysql);
    MYSQL_ROW row = mysql_fetch_row(result);
    std::string nickname = row[0];
    mysql_free_result(result);
    mysql_close(mysql);
    return nickname;
}

void UserMgt::add_user_rela(std::string nickname_1,std::string nickname_2,std::string rela)
{   
    std::string id_1 = std::to_string(id_of_nickname(nickname_1));
    std::string id_2 = std::to_string(id_of_nickname(nickname_2));

    MYSQL* mysql;
    mysql_my_init(mysql);

    //std::cout << "0" << std::endl;

    // 查询用户记录是否已经存在
    int count = 0;
    std::string query = 
    "SELECT COUNT(*) FROM user_relationship WHERE id_1 = " + id_1 + " AND id_2 = " + id_2 + " AND relationship = '" + rela + "'";
    mysql_query(mysql, query.c_str());
    MYSQL_RES* result = mysql_store_result(mysql);
    if(result != nullptr)
    {
        MYSQL_ROW row;
        row = mysql_fetch_row(result);
        count += atoi(row[0]);
        mysql_free_result(result);
    }
    else
        std::cout << "result is null";
    

    //std::cout << "1" << std::endl;
    
    query = 
    "SELECT COUNT(*) FROM user_relationship WHERE id_1 = " + id_2 + " AND id_2 = " + id_1 + " AND relationship = '" + rela + "'";
    mysql_query(mysql, query.c_str());
    result = mysql_store_result(mysql);
    if(result != nullptr)
    {
        MYSQL_ROW row;
        row = mysql_fetch_row(result);
        count += atoi(row[0]);
        mysql_free_result(result);
    }
    else
        std::cout << "result is null";

    //std::cout << "2" << std::endl;
    
    if(count != 0)
    {
        std::cout << "已存在用户关系，不插入新纪录" << std::endl;
        return;
    }

    query = 
    "INSERT INTO user_relationship (id_1, id_2, relationship) VALUES (" + id_1 + ", " + id_2 + ", '" + rela + "')";
    mysql_query(mysql, query.c_str());
    query = 
    "INSERT INTO user_relationship (id_1, id_2, relationship) VALUES (" + id_2 + ", " + id_1 + ", '" + rela + "')";
    mysql_query(mysql, query.c_str());

    mysql_close(mysql);

    flush_qml_friend_list(id_of_nickname(nickname_1));
    flush_qml_friend_list(id_of_nickname(nickname_2));
}


void UserMgt::flush_qml_friend_list(int id) // 刷新某个用户的好友列表
{
    MYSQL* mysql;
    mysql_my_init(mysql);

    std::string query = 
    "SELECT id_2 FROM user_relationship WHERE id_1 = " + std::to_string(id) + " AND relationship = '" + "friend" + "'";

    mysql_query(mysql, query.c_str());
    MYSQL_RES* result = mysql_store_result(mysql);
    if(result != nullptr)
    {
        MYSQL_ROW row;
        while ((row = mysql_fetch_row(result)) != nullptr) 
        {
            // 遍历每一行的数据
            int friend_id = atoi(row[0]);
            std::cout << "friend_id: " << friend_id << std::endl;
            send_friend_item_info_to_qml(id, friend_id);
        }
        mysql_free_result(result);
    }
    else
        std::cout << "result is null";
}

void UserMgt::send_friend_item_info_to_qml(int recv_id, int friend_id)
{
    Json::Value root;
    root["op"] = "have_friend_item";
    //root["id"] = std::to_string(friend_id);
    root["id"] = friend_id;
    std::string jsonString = root.toStyledString();
    send_to_qml::send_text(hdl_of_user(nickname_of_id(recv_id)), jsonString);
}


void UserMgt::set_user_info(int id, std::string* info)
{
    std::string nickname = info[0];
    std::string gender = info[1];
    std::string tele = info[2];
    std::string signature = info[3];

    MYSQL* mysql;
    mysql_my_init(mysql);

    std::string query = 
    "UPDATE user SET nickname = '" + nickname + "', gender = '" + gender 
    + "', telnum = '" + tele + "', signature = '" + signature + "' WHERE id = " + std::to_string(id);

    //std::cout << query << std::endl;

    mysql_query(mysql, query.c_str());
    mysql_close(mysql);

    Json::Value json_value;
    json_value["op"] = "popup_msg";
    json_value["kind"] = "yes";
    json_value["reason"] = "信息修改成功!";
    std::string str = json_value.toStyledString();
    send_to_qml::send_text(hdl_of_user(nickname_of_id(id)), str);

    Json::Value value;
    value["op"] = "flush_user_info";
    std::string s = value.toStyledString();
    send_to_qml::send_text(hdl_of_user(nickname_of_id(id)), s);
}


std::string UserMgt::info_of_user(int id, std::string colum) // 从数据库查询用户信息，某个字段的内容
{
    // 设置数据库
    MYSQL* mysql;
    mysql_my_init(mysql);
    std::string ret = "";

    // 查询
    std::string query = "SELECT " + colum + " FROM user WHERE id = '" + std::to_string(id) + "'";
    mysql_query(mysql, query.c_str());
    MYSQL_RES* result = mysql_store_result(mysql);
    MYSQL_ROW row = mysql_fetch_row(result);
    if(row[0] == nullptr)
    {
        std::cout << "UserMgt::info_of_user 查询失败，字段：" << colum << std::endl;
    }
    else
    {
        ret = row[0];
    }
    
    mysql_free_result(result);
    mysql_close(mysql);

    return ret;
}




void UserMgt::flush_user_info_with_name(std::string user_name,con_hdl hdl, server *s)
{
    // 查询用户昵称
    int user_id = id_of_nickname(user_name);
    

    // 查询用户个性签名
    std::string signature = info_of_user(user_id, "signature");
    std::string gender = info_of_user(user_id, "gender");
    std::string tele = info_of_user(user_id, "telnum");
    std::string m_time = info_of_user(user_id, "m_time");
    

    // 告诉客户端,用户的昵称等
    Json::Value root;
    root["op"] = "info";
    root["user_id"] = user_id;
    root["signature"] = signature;
    root["gender"] = gender;
    root["tele"] = tele;
    root["m_time"] = m_time;
    std::string jsonString = root.toStyledString();
    send_to_qml::send_text(hdl, jsonString);
	
    
    // 调用文件传输模块的方法, 把此 id 用户的头像, 发送到连接 hdl 上
    file_mgt_.send_user_avatar(user_id, hdl, s);
}